package org.tbwork.utility.httprr;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpCookie;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.json.JSONObject;
import org.json.JSONArray;
import org.jsoup.nodes.Element;
import org.apache.http.ParseException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.util.EntityUtils;
import org.apache.http.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class Response{

	private final static Logger logger=LoggerFactory.getLogger(Response.class);
	private CloseableHttpResponse response= null;
	private String pageEncoding ="utf-8";
	private String redirectUrl;
    private byte [] responseByte;
    
	/** Get response txt in specified pageEncode
	 * @param pageEncode 
	 * @return response in Text.
	 */
	public String getText(String pageEncode){
		if(response!=null)
		{
			try
			{
				if(pageEncode.equals("utf-8"))
				{
					String resText = new String(responseByte,"utf-8");
				    return  resText;
				}
				else
				{
					String resText = new String(responseByte,"gb2312");
				    return  resText;
				} 
			}
			catch(Exception e)
			{
				logger.error("Parse response to text failed. Detailed message: {} ", e.getMessage()); 
				return "";
			}
			finally{
				  
			}
		}
	    else
			return "";
	}
	
	public int getStatus(){
		if(response!=null)
		{
			 StatusLine sl = response.getStatusLine(); 
			 return sl.getStatusCode() ;
		}
	    else
	    	return 0;
	}
	
	/** Default pageEncode: utf-8
	 * @return 
	 */
	public String getText(){
		return getText(pageEncoding);
	}
	

	public Document getDocument(String pageEncode)
	{
		 String text = getText(pageEncode);
		 if(!text.isEmpty())
		 {
			 try {
				 return  Jsoup.parse(text);
			 } catch (Exception e) { 
				e.printStackTrace();
				logger.error("The response content is not a valid HTML document!");
				return null;
			 }
		 }
		 else {
			 logger.info(String.format("The response is empty."));
			 return null;
		}
	}
	

	public Document getDocument() throws Exception
	{
		return getDocument(pageEncoding);
	}
	
	
    public Elements getElementsByCss(String cssText, String pageEncode){
    	
    	 Document doc = getDocument(pageEncode);
		 if( doc != null )
		 {
		 	 return  doc.select(cssText);
		 }
		 else {
			 logger.info("The response content is empty.");
			 return null;
		}
	}
    
    public Elements getElementsByCss(String cssText){
       return  getElementsByCss(pageEncoding);
    }
    
    
    public JSONObject getJsonObject(String pageEncode)
    {
    	 String text = getText(pageEncode);
		 if(!text.isEmpty())
		 {
			 try {
				 JSONObject object = new JSONObject(text);
				 return  object;
			 } catch (Exception e) { 
				 
				logger.error("The response content is not a valid JSON object!");
				return null;
			 }
		 }
		 else {
			 logger.info("The response content is empty.");
			 return null;
		}
    }
    
    public JSONArray getJsonArray(String pageEncode)
    {
    	 String text = getText(pageEncode);
		 if(!text.isEmpty())
		 {
			 try {
				 JSONArray object = new JSONArray(text);
				 return  object;
			 } catch (Exception e) { 
				 
				logger.error("The response content is not a valid JSON object!");
				return null;
			 }
		 }
		 else {
			 logger.info("The response content is empty.");
			 return null;
		}
    }
   
    public String getJsonText(String pageEncode) throws Exception
    {
    	 String text = getText(pageEncode);
		 if(!text.isEmpty())
		 {
			 try {
				  if(text.charAt(0)=='[')
					  return jsonArray2Text();
				  else
					  return jsonObject2Text();
			 } catch (Exception e) { 
				 
				logger.error("The response content is not a valid JSON object!");
				return null;
			 }
		 }
		 else {
			 logger.info("The response content is empty.");
			 return null;
		}
    }
    
    /*
     * Default pageEncode: utf-8
     */
    public JSONObject getJsonObject() throws Exception
    {
    	 return  getJsonObject(pageEncoding);
    }
    
    /*
     * Default pageEncode: utf-8
     */
    public JSONArray getJsonArray() throws Exception
    {
    	 return  getJsonArray(pageEncoding);
    }
    
    /*
     * Default pageEncode: utf-8
     */
    public String getJsonText() throws Exception
    {
    	return getJsonText(pageEncoding);
    }
    
    
    private String jsonArray2Text(){
    	com.alibaba.fastjson.JSONArray json = com.alibaba.fastjson.JSON.parseArray(getText());
    	return com.alibaba.fastjson.JSON.toJSONString(json, true);
    }
    
    private String jsonObject2Text(){
    	com.alibaba.fastjson.JSONObject json = com.alibaba.fastjson.JSON.parseObject(getText());
    	return com.alibaba.fastjson.JSON.toJSONString(json, true);
    }
    
	private CloseableHttpResponse getResponse(){
		return response;
	}
	
	protected void setResponse(CloseableHttpResponse response){
     try {
    	 
    	 	 this.response = response;
    	 	 
    	 	 if( response == null ) return ;
    	 	 HttpEntity entity = response.getEntity();
    	 	 
			 if( entity == null )   
			 {     
				 if(response.getHeaders("Location") != null && response.getHeaders("Location").length >= 1)
				 {
					 redirectUrl =   response.getHeaders("Location")[0].getValue();
				 }
				 
				 return;
			 }
			  
			 InputStream responseBuffer =  entity.getContent();
			 if(responseBuffer == null){
				 return;
			 }
			 responseByte =   input2byte(responseBuffer); 
		 
		} catch (IllegalStateException e) { 
			logger.error("Fail to load data from the socket buffer. Detailed message: "+e.getMessage());
		} catch (IOException e) { 
			logger.error("Fail to load data from the socket buffer. Detailed message: "+e.getMessage());
		}
	}
	
	private static final byte[] input2byte(InputStream inStream) throws IOException {  
	          
	        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();  
	        byte[] buff = new byte[4096];  
	        int rc = 0;  
	        while ((rc = inStream.read(buff, 0, 4096)) > 0) {  
	            swapStream.write(buff, 0, rc);  
	        }   
	        return swapStream.toByteArray();  
    }  
	   
	public Header [] getHeaders(String headName)
	{
		return response.getHeaders(headName);
	}

	/** If HTTP return STATUS of 30X, and you did not use auto redirection,
	 *  you can get the redirect url by calling this.
	 * @return
	 */
	public String getRedirectUrl() {
		return redirectUrl;
	}

	public void setRedirectUrl(String redirectUrl) {
		this.redirectUrl = redirectUrl;
	}
	
	
}
